package erfgame.core.world.terrain.file;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;


import erfgame.core.Point3D;
import erfgame.core.dao.ObjectDAO;
import erfgame.core.entity.Entity;
import erfgame.core.world.terrain.BlockEntityPositions;

public class FileBlockEntityPositionObjectDAO implements
		ObjectDAO<Point3D, BlockEntityPositions> {
	
	private static final Logger log = Logger.getLogger( FileBlockEntityPositionObjectDAO.class.getName() );
	
	private File baseDirectory;
	
	private FileStreamFactory streamFactory;
	private ObjectDAO<Long, Entity> entityDAO;
	
	public FileBlockEntityPositionObjectDAO(
			File baseDirectory,
			FileStreamFactory streamFactory, 
			ObjectDAO<Long, Entity> entityDAO 
	) {
		this.baseDirectory = baseDirectory;
		this.streamFactory = streamFactory;
		this.entityDAO = entityDAO;
	}
	
	private File getFile( Point3D key ) {
		return new File( baseDirectory, ""+key.x+"x"+key.y+"x"+key.z+".pos");
	}

	public boolean containsObject(Point3D key) {
		return getFile( key ).exists();
	}

	public boolean removeObject(Point3D key) {
		return getFile( key ).delete();
	}

	public BlockEntityPositions retrieveObject(Point3D key) {
		File file = getFile( key );
		if( file.exists() ) {
			DataInputStream ins = null;
			try {
				ins = new DataInputStream( streamFactory.openInputStream(file) );
				int size = ins.readInt();
				ArrayList<Entity> entities = new ArrayList<Entity>( size );
				for( int i=size; i>0; ) {
					i--;
					long id = ins.readLong();
					Entity entity = entityDAO.retrieveObject(id);
					entities.add( entity );
				}
				return new BlockEntityPositions( entities );
			} catch( Exception ex ) {
				throw new RuntimeException( "unable to open "+file, ex );
			} finally {
				if( ins != null ) {
					try {
						ins.close();
					} catch( Exception ex ) {
						log.log( Level.WARNING, "unable to close stream to "+file, ex );
					}
					
				}
			}
		} else {
			return new BlockEntityPositions();
		}
	}

	public void storeObject(Point3D key, BlockEntityPositions object) {
		File file = getFile( key );
		DataOutputStream outs = null;
		try {
			List<Entity> entities = object.getEntities();
			outs = new DataOutputStream( streamFactory.openOutputStream(file) );
			outs.writeInt( entities.size() );
			for( int i=entities.size(); i>0; ) {
				i--;
				Entity entity = entities.get( i );
				long id = entity.getId();
				outs.writeLong( id );
			}
		} catch( Exception ex ) {
			throw new RuntimeException( "unable to open "+file, ex );
		} finally {
			if( outs != null ) {
				try {
					outs.close();
				} catch( Exception ex ) {
					log.log( Level.WARNING, "unable to close stream from "+file, ex );
				}
			}
		}
	}

}
